﻿/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is tyzoh.jp code.
 *
 * The Initial Developer of the Original Code is Kazutaka Kurihara.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */
using System;
using System.Windows.Forms;
using PluginInterface;
using Qurihara;
using System.Collections;
using System.Drawing;
using Microsoft.Ink;
using Qurihara.QBasic;
using System.Diagnostics; // for Debug

namespace KotodamaPlugin.ViewWritePlugin
{
	public class ViewWriteMode : Mode
	{

        //event for strokecreated
        public event StrokeElementCreatedEventHandler StrokeElementCreated = null;
        public delegate void StrokeElementCreatedEventHandler(object sender, StrokeElementCreatedEventArgs e);
        public class StrokeElementCreatedEventArgs : EventArgs
        {
            public StrokeElementCreatedEventArgs(StrokeElement se)
            {
                StrokeElement = se;
            }
            public StrokeElement StrokeElement;
        }

        // for view
        internal ShuttleControl.RShuttleControl sf;
        protected System.Windows.Forms.Cursor cursor;
        protected bool dragInFlag = false;

        //event for viewmoved by pen
        public event ViewMovedEventHandler ViewMovedCreated = null;
        public delegate void ViewMovedEventHandler(object sender, ViewMovedEventArgs e);
        public class ViewMovedEventArgs : EventArgs
        {
            public ViewMovedEventArgs(Rectangle newViewRect)
            {
                ViewRectangle = newViewRect;
           }
            public Rectangle ViewRectangle;
        }

        protected InkCollectorStrokeEventHandler se;

        protected IKotodamaBase kotodama; 
		public ViewWriteMode(IKotodamaBase k)
		{
            kotodama = k;

            //write
            se = new InkCollectorStrokeEventHandler(Stroke_Event);

            //view
            cursor = System.Windows.Forms.Cursors.Hand;

            sf = new ShuttleControl.RShuttleControl();

            sf.TicksPerRound = 16;//4;
            sf.OnShuttleTickFwd += new EventHandler(this.StepFwd);
            sf.OnShuttleTickBack += new EventHandler(this.StepBack);

            sf.Width = 96;// 128;
            sf.Height = 96;// 128;

            UpdateShuttlePosition();

            Control c = (Control)kotodama.EnvironmentTable["Base.Form"];
            c.Resize += new EventHandler(Control_Resize);
		}

        void Control_Resize(object sender, EventArgs e)
        {
            UpdateShuttlePosition();
        }

        private void UpdateShuttlePosition()
        {
            Control c = (Control)kotodama.EnvironmentTable["Base.Form"];
            //if(c == null) c = kotodama.Control;

            int offsetY = 0;
            //if (kotodama.ToolBarManager == null)
            //{
            //    offsetY = 40;
            //    sf.Location = new Point(0,
            //        c.ClientRectangle.Top + offsetY);
            //}
            //else
            //{
                sf.Location = new Point(c.ClientRectangle.Right - sf.Width,
                    c.ClientRectangle.Bottom - sf.Height);
                //kotodama.Control.ClientRectangle.Top);
            //}
        }

		protected override void Init()
		{
            //write
            kotodama.InkCollector.Stroke += se;
            //kotodama.InkCollector.Stroke += new InkCollectorStrokeEventHandler(Stroke_Event);

			kotodama.InkCollector.CollectionMode = CollectionMode.InkOnly;
			kotodama.InkCollector.Enabled = true;
			FigureElement.LockInvalidate = true;

            //view
            sf.OnMouseDownNotShuttle += new MouseEventHandler(MouseDown);
            sf.OnMouseUpNotShuttle += new MouseEventHandler(MouseUp);
            sf.OnMouseMoveNotShuttle += new MouseEventHandler(MouseMove);
            kotodama.Control.Cursor = cursor;
            //kotodama.Control.Controls.Add(sf);
            Control c = (Control)kotodama.EnvironmentTable["Base.Form"];
            c.Controls.Add(sf);
            sf.BringToFront();

            sf.Visible = true;
            sf.Enabled = true;

            kotodama.Control.MouseDown += new MouseEventHandler(Control_MouseDown);
            //kotodama.Control.MouseMove += new MouseEventHandler(Control_MouseMove);
            //kotodama.Control.MouseUp += new MouseEventHandler(Control_MouseUp);

            //kotodama.InkCollector.MouseDown += new InkCollectorMouseDownEventHandler(InkCollector_MouseDown);
            //kotodama.InkCollector.MouseMove += new InkCollectorMouseMoveEventHandler(InkCollector_MouseMove);
            //kotodama.InkCollector.MouseUp += new InkCollectorMouseUpEventHandler(InkCollector_MouseUp);

            kotodama.Control.MouseMove +=new MouseEventHandler(MouseMove);


            //general
            Form f = (Form)kotodama.EnvironmentTable["Base.Form"];
            if (f != null) f.Activate();
		}

        //void InkCollector_MouseUp(object sender, CancelMouseEventArgs e)
        //{
        //    MouseUp(sender, e);
        //}

        //void InkCollector_MouseMove(object sender, CancelMouseEventArgs e)
        //{
        //    MouseMove(sender, e);
        //}

        //void InkCollector_MouseDown(object sender, CancelMouseEventArgs e)
        //{
        //    if (e.Button == MouseButtons.Right)
        //    {
        //        dragInPoint = new Point(e.X, e.Y);
        //        buttons = e.Button;
        //        dragInFlag = true;
        //        prevP = dragInPoint;
        //    }
        //}

        //void Control_MouseUp(object sender, MouseEventArgs e)
        //{
        //    MouseUp(sender, e);
        //}

        //void Control_MouseMove(object sender, MouseEventArgs e)
        //{
        //    MouseMove(sender, e);
        //}

        void Control_MouseDown(object sender, MouseEventArgs e)
        {
            buttons = e.Button;
            if (e.Button == MouseButtons.Right)
            {
                dragInPoint = new Point(e.X, e.Y);
                //buttons = e.Button;
                dragInFlag = true;
                prevP = dragInPoint;
            }
        }

		protected override void End()
		{
            //view
            //kotodama.Control.MouseDown -= new MouseEventHandler(Control_MouseDown);
            //kotodama.Control.MouseMove -= new MouseEventHandler(Control_MouseMove);
            //kotodama.Control.MouseUp -= new MouseEventHandler(Control_MouseUp);

            sf.OnMouseMoveNotShuttle -= new MouseEventHandler(MouseMove);
            sf.OnMouseDownNotShuttle -= new MouseEventHandler(MouseDown);
            sf.OnMouseUpNotShuttle -= new MouseEventHandler(MouseUp);

            kotodama.Control.Cursor = System.Windows.Forms.Cursors.Default;

            Control c = (Control)kotodama.EnvironmentTable["Base.Form"];
            c.Controls.Remove(sf);
            //kotodama.Control.Controls.Remove(sf);
            sf.Visible = false;
            sf.Enabled = false;

            //write
            kotodama.InkCollector.Stroke -= se;
            //kotodama.InkCollector.Stroke -= new InkCollectorStrokeEventHandler(Stroke_Event);

			kotodama.InkCollector.Enabled = false;
			FigureElement.LockInvalidate = false;
        }

        #region write

        // 書いてからストローク生成までの遅れ（ｍｓ）
		// これは処理速度が落ちてきたとき用。
		//public static int StrokeCreateDelay = 500;

        //int previd=-1;
		public void Stroke_Event(object sender, InkCollectorStrokeEventArgs e)
		{
            if (dragInFlag)
            {
                dragInFlag = false;
                e.Cancel = true;
                kotodama.InkCollector.Ink.DeleteStroke(e.Stroke);
                return;
            }
/*
			strokeGenerateQueue.Enqueue(e.Stroke);
			Qurihara.Anm.WaitAnm anm = new Qurihara.Anm.WaitAnm(StrokeCreateDelay);
			anm.AnmFinishedHandler += new EventHandler(Create_Stroke);
			anm.Start();

			e.Cancel = false;
*/
            //// このコードはXPでなぜか１ストロークにつき２回strokeeventがFireすることに対処するためのもの。
            //// このバグはmicrosoft.ink.dllのバージョンに依存する。
            //int id = e.Stroke.Id;
            //if (id == previd)
            //{
            //    e.Cancel = false;// true; //trueにするとAutoRendering=falseなので描画で落ちる
            //    return;
            //}
            //previd = id;
            //// このコードはXPでなぜか１ストロークにつき２回strokeeventがFireすることに対処するためのもの。＊＊＊

			Rectangle re;
            //Debug.WriteLine(this.GetType().ToString() + ".Stroke_Event");

			re = new Rectangle(e.Stroke.GetBoundingBox().Location,e.Stroke.GetBoundingBox().Size);
			//GetViewBoundingBoxFromInk(kotodama.Form.Handle,ref re, kotodama.InkCollector,kotodama.Presentation.CurrentSlide.View);
			InkUtil.GetViewBoundingBoxFromInk(kotodama.Control,ref re, kotodama.InkCollector,kotodama.Presentation.CurrentSlide.View);
			Stroke s = e.Stroke;
            //if (s.Id == prevStroke.Id) return;
            //if (re.Equals(prevRec)) return;
			kotodama.Presentation.CurrentSlide.View.InkScreenToInkView(ref s);
			FigureElement fe = kotodama.Presentation.CurrentSlide.createStroke(-1,re,s);
			e.Cancel = false;

			s.DrawingAttributes.Width = ViewDependentLength(
				(int)kotodama.InkCollector.DefaultDrawingAttributes.Width);
			s.DrawingAttributes.Height = ViewDependentLength(
				(int)kotodama.InkCollector.DefaultDrawingAttributes.Height);

            if(StrokeElementCreated != null) StrokeElementCreated(this,new StrokeElementCreatedEventArgs((StrokeElement)fe));
		}
		private int ViewDependentLength(int lengthInScreen)
		{
			// 書くときのサイズがだめ。結果はＶｉｅｗ非依存
			//return lengthInScreen;
//			書くときのサイズがだめ。結果はＶｉｅｗ依存
			Point [] ps = new Point[2];
			ps[0] = new Point(0,0);
			ps[1] = new Point(0,lengthInScreen);//,0);
			Qurihara.InkView view =
				kotodama.Presentation.CurrentSlide.View;
			view.InkScreenToInkView(ref ps);
			//view.InkViewToInkScreen(ref ps);
			return ps[1].Y - ps[0].Y;

        }
        #endregion

        #region view

        private Point dragInPoint;
        private MouseButtons buttons;
        protected void MouseDown(object o, System.Windows.Forms.MouseEventArgs e)
        {
            buttons = e.Button;
            if (!dragInFlag)
            {
                dragInPoint = new Point(e.X, e.Y);
                //buttons = e.Button;
                dragInFlag = true;
                //kotodama.Form.MouseMove += me;
                prevP = dragInPoint;
            }
        }
        private Point prevP;
        private void MouseMove(object sender, MouseEventArgs e)
        {
            //			if (wa.IsActive) wa.Abort();
            //			sf.Visible = true;
            //			wa.Init();
            //			wa.Start();

            if (dragInFlag)
            {
                Point p = new Point(e.X, e.Y);
                MoveView(prevP, p);
                prevP = p;
            }

            if (buttons != MouseButtons.Right && e.Button == MouseButtons.Right)
            {
                dragInPoint = new Point(e.X, e.Y);
                buttons = e.Button;
                dragInFlag = true;
                prevP = dragInPoint;
            }

        }
        private Point dragOutPoint;
        protected void MouseUp(object o, System.Windows.Forms.MouseEventArgs e)
        {
            if (dragInFlag)
            {
                dragOutPoint = new Point(e.X, e.Y);
                dragInFlag = false;
                //kotodama.Form.MouseMove -= me;

                //switch (buttons)
                //{
                //    case MouseButtons.Left:
                //    default:
                //        //MoveView(dragInPoint,dragOutPoint);
                //        break;
                //    case MouseButtons.Right:
                //        ZoomView(dragInPoint, dragOutPoint);
                //        break;
                //}
            }
        }

        private int MAX = 30000;
        private int MIN = 30;
        private void MoveView(Point inP, Point outP)
        {
            Point[] ps = { inP, outP };
            // 点ではなく増分を変換するとおかしなことになる。 PointではなくSizeを使うべき。
            kotodama.Presentation.CurrentSlide.View.ScreenToView(ref ps);
            Point p = new Point(ps[1].X - ps[0].X, ps[1].Y - ps[0].Y);
            Rectangle r = kotodama.Presentation.CurrentSlide.View.ViewRectangle;
            r.X -= p.X;
            r.Y -= p.Y;
            kotodama.Presentation.CurrentSlide.View.ViewRectangle = r;
            FireViewMoved(r);
            kotodama.Control.Invalidate();
        }
        private void ZoomView(Point inP, Point outP)
        {
            //Screen座標の中心点が変わらないように変換する。
            Point[] ps = { inP, outP };
            kotodama.Presentation.CurrentSlide.View.ScreenToView(ref ps);
            Point p = new Point(ps[1].X - ps[0].X, ps[1].Y - ps[0].Y);
            ZoomView(p.Y);
        }
        private void ZoomView(int z)
        {
            float aspect = (float)kotodama.Presentation.CurrentSlide.View.ScreenSize.Width
                / (float)kotodama.Presentation.CurrentSlide.View.ScreenSize.Height;
            Rectangle r = Rectangle.Inflate(kotodama.Presentation.CurrentSlide.View.ViewRectangle, (int)(z * aspect), z);
            if (r.Height < MAX && r.Height > MIN)
            {
                kotodama.Presentation.CurrentSlide.View.ViewRectangle = r;
                FireViewMoved(r);
                kotodama.Control.Invalidate();
            }
            else
            {
                //MessageBox.Show("ズームの限界です。");
            }
        }

        public void StepFwd(object o, EventArgs e)
        {
            int zoom =
                (int)(kotodama.Presentation.CurrentSlide.View.ViewRectangle.Height * 0.04);//*0.25);
            ZoomView(-zoom);
        }
        public void StepBack(object o, EventArgs e)
        {
            int zoom =
                (int)(kotodama.Presentation.CurrentSlide.View.ViewRectangle.Height * 0.04);//*0.25);
            ZoomView(zoom);
        }

        private void FireViewMoved(Rectangle r)
        {
            if (ViewMovedCreated != null)
                ViewMovedCreated(this,new ViewMovedEventArgs(r));
        }
        #endregion
    }
}